/*
 * @Author: hongbin
 * @Date: 2023-08-07 22:22:28
 * @LastEditors: hongbin
 * @LastEditTime: 2023-08-11 22:27:32
 * @Description: 空间站
 */
import { ThreeHelper } from "@/ThreeHelper";
import { CameraInject } from "@/decorators";
import { DotMaterial } from "@/shader/DotMaterial";
import { Points } from "three";
import { gsap } from "gsap";
import { GUIControl } from "@/ThreeHelper/utils/GUIControl";
import { RingPoint } from "./RingPoint";

@(CameraInject<typeof Station>)
export class Station {
    particle?: THREE.Points<THREE.BufferGeometry, THREE.ShaderMaterial>;
    private camera!: THREE.PerspectiveCamera;
    private cameraWrapper!: THREE.Object3D;

    constructor() {
        this.loadModel();
    }

    loadModel() {
        ThreeHelper.instance
            .loadDrc("/models/particles/station.drc")
            .then((geo) => {
                console.log(geo);
                geo.setAttribute("aColor", geo.attributes.color);
                geo.deleteAttribute("color");
                geo.center();
                geo.rotateY(Math.PI / 2);
                this.particle = new Points(
                    geo,
                    new DotMaterial(
                        {
                            near: 20,
                            far: -30,
                            fadeDistance: 0,
                            blur: 0,
                            minOpacity: 0,
                            maxOpacity: 0,
                        },
                        {
                            USE_ACOLOR: true,
                        }
                    )
                );

                ThreeHelper.instance.add(this.particle);
                this.setAnimation();
                new GUIControl(ThreeHelper.instance.gui!, this.particle, 1000);
            });
    }

    setAnimation() {
        const particle = this.particle;
        if (!particle) return;
        // particle.position.y = 8;
        // particle.position.x = -18;
        particle.position.z = -70;
        particle.scale.set(-1, 1, 1);
        particle.rotation.x = 0.35;

        const tl = gsap.timeline({
            scrollTrigger: {
                trigger: "#container",
                start: 0,
                end: innerHeight,
                scrub: 1,
            },
        });
        const delay = 0.03;
        tl.to(particle.position, { z: 50, y: -15 }, delay);
        tl.to(particle.rotation, { y: 0.5 }, delay);
        tl.to(
            particle.material.uniforms.minOpacity,
            { value: 0.2, duration: 0.1 },
            delay
        );

        tl.to(
            particle.material.uniforms.maxOpacity,
            { value: 0.23, duration: 0.2 },
            delay
        );

        tl.to(
            particle.material.uniforms.fadeDistance,
            { value: 7, duration: 0.05 },
            delay + 0.15
        );
        tl.to(
            particle.material.uniforms.minOpacity,
            { value: 0, duration: 0.1 },
            delay + 0.1
        );
        tl.to(
            particle.material.uniforms.blur,
            { value: 8, duration: 0.05 },
            delay + 0.15
        );

        this.setRingPoint(tl);
    }

    setRingPoint(timeline: gsap.core.Timeline) {
        const ringConfig = [{ z: 0 }, { z: 6 }, { z: 11 }, { z: 15 }];
        const pos: Vector3[] = [];
        const opacity: THREE.IUniform[] = [];

        for (const { z } of ringConfig) {
            const ringPoint = new RingPoint();
            ringPoint.math.position.z = z - 15;
            ThreeHelper.instance.add(ringPoint.math);
            pos.push(ringPoint.math.position);
            ringPoint.math.material.uniforms.maxOpacity.value = 0;
            opacity.unshift(ringPoint.math.material.uniforms.maxOpacity);
        }

        const ringPoint = new RingPoint();
        ringPoint.math.position.z = -10;
        ThreeHelper.instance.add(ringPoint.math);

        timeline.to(
            pos,
            {
                ease: "power3.inOut",
                duration: 0.02,
                z: (i) => ringConfig[i].z,
                stagger: {
                    each: 0.002,
                },
            },
            0
        );
        timeline
            .to(
                opacity,
                {
                    ease: "power3.inOut",
                    duration: 0.03,
                    value: 0.6,
                    stagger: {
                        each: 0.002,
                    },
                },
                0
            )
            .to(
                [...pos].reverse(),
                {
                    z: 40,
                    ease: "power3.inOut",
                    duration: 0.2,
                    stagger: {
                        each: 0.02,
                    },
                },
                0.03
            )
            .to(
                ringPoint.math.position,
                {
                    z: 40,
                    ease: "power3.inOut",
                    duration: 0.2,
                },
                0.2
            );
    }
}
